package compiler.lexer;

import compiler.error.ErrorHandler;
import compiler.input.Input;

import java.util.ArrayList;
import java.util.Objects;


public class RegularExpressionHandler {
    private Input input = null;
    private MacroHandler macroHandler = null;
    private ArrayList<String> regularExprArr = new ArrayList<String>();
    private boolean inquoted = false;

    public RegularExpressionHandler(Input input, MacroHandler macroHandler) {
        this.input = input;
        this.macroHandler = macroHandler;

        System.out.println("Enter regular expression");

        input.readInput();

        preProcessReg();

        StringBuilder builder = new StringBuilder();
        regularExprArr.forEach(builder::append);

        System.out.println("processed regular expression:" + builder.toString());
    }


    private void preProcessReg() {
        /*
         * 对正则表达式进行预处理，将表达式中的宏进行替换，例如
		 * D*\.D 预处理后输出
		 * [0-9]*\.[0-9]
		 * 注意，宏是可以间套的，所以宏替换时要注意处理间套的情形
		 */

        //去掉开头的空格或空行
        while (Input.isSkipChar(input.lookAhead())) {
            input.advance();
        }

        String regularExpr = "";
        int character = input.lookAhead();
        while (!Objects.equals(Input.EOF, character)) {

            character = input.advance();

            if (character == '"') {
                //不处理双引号的中的字符
                inquoted = !inquoted;

            } else if (!inquoted && character == '{') {
                String name = extractMacroName();
                regularExpr += expandMacro(name);

            } else {
                regularExpr += (char) character;
            }

            character = input.lookAhead();
        }

        regularExprArr.add(regularExpr);
    }

    private String expandMacro(String macroName) {
        String macroContent = macroHandler.expandMacro(macroName);

        int begin = macroContent.indexOf('{');
        while (begin != -1) {
            int end = macroContent.indexOf('}', begin);
            if (end == -1) {
                ErrorHandler.parseErr(ErrorHandler.Error.E_BADMAC);
                return null;
            }

            boolean inquoted = checkInQuoted(macroContent, begin, end);

            if (!inquoted) {
                macroName = macroContent.substring(begin + 1, end);
                String content = macroContent.substring(0, begin);
                content += macroHandler.expandMacro(macroName);
                content += macroContent.substring(end + 1, macroContent.length());
                macroContent = content;
                //如果宏替换后，替换的内容还有宏定义，那么继续替换，直到所有宏都替换完为止
                begin = macroContent.indexOf('{');
            } else {
                begin = macroContent.indexOf('{', end);
            }

        }

        return macroContent;
    }

    private boolean checkInQuoted(String macroContent, int curlyBracesBegin, int curlyBracesEnd) {
        /*
         * 先查找距离 { 最近的一个 双引号
		 * 然后查找第二个双引号
		 * 如果双括号{}在两个双引号之间
		 * 那么inquoted设置为 true
		 */
        boolean inquoted = false;
        int quoteBegin = macroContent.indexOf('"');
        int quoteEnd;

        while (quoteBegin != -1) {

            quoteEnd = macroContent.indexOf('"', quoteBegin + 1);
            if (quoteEnd == -1) {
                ErrorHandler.parseErr(ErrorHandler.Error.E_BADMAC);
            }

            if (quoteBegin < curlyBracesBegin && quoteEnd > curlyBracesEnd) {
                /*
                 * "{ ... }"
				 */
                inquoted = true;

            } else if (quoteBegin > curlyBracesBegin
                    && quoteBegin < curlyBracesEnd
                    && quoteEnd > curlyBracesEnd) {
				/* "{" ... }
				 * 大括号不匹配
				 */
                ErrorHandler.parseErr(ErrorHandler.Error.E_BADMAC);

            } else if (quoteEnd > curlyBracesBegin
                    && quoteEnd < curlyBracesEnd
                    && quoteBegin > curlyBracesBegin) {
				/*  {...."}"
				 * 大括号不匹配
				 */
                ErrorHandler.parseErr(ErrorHandler.Error.E_BADMAC);
            }

            //往右继续找 "" 重复上述步骤
            quoteBegin = macroContent.indexOf('"', quoteEnd + 1);
        }

        return inquoted;
    }

    public int getRegularExpressionCount() {
        return regularExprArr.size();
    }

    public String getRegularExpression(int index) {
        if (index < 0 || index >= regularExprArr.size()) {
            return null;
        }

        return regularExprArr.get(index);
    }

    private String extractMacroName() {
        String name = "";
        char character = (char) input.advance();
        while (character != '}' && character != '\n') {
            name += character;
            character = (char) input.advance();
        }

        if (character == '}') {
            return name;
        }

        ErrorHandler.parseErr(ErrorHandler.Error.E_BADMAC);
        return null;
    }
}
